package com.coship.acf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CacheServers {
	private static Logger logger = LoggerFactory.getLogger(CacheServers.class);
	
	private static Map<String,CacheServer> activeServers = new HashMap<String, CacheServer>();
	
	private static Map<String,CacheServer> downServers = new HashMap<String, CacheServer>();
	
	private static ThreadLocal<String> shardToken = new ThreadLocal<String>();
	
	public static void setShardToken(String token) {
		shardToken.set(token);
	}

	public static CacheServer getShardServer() {
		if(getActiveServers().size() == 0){
			return new EmptyCacheServer();
		}
		int shard = getShard();
		return getActiveServers().get(shard);
	}
	
	public static int getShard() {
		String token = shardToken.get();
		token = token == null ? "0" : token;
		int hash =  Math.abs(token.hashCode());
		return hash % activeServers.size();
	}
	
	public static boolean isActive() {
		return activeServers.size() > 0;
	}
	
	public static List<CacheServer> getActiveServers() {
		List<CacheServer> servers = new ArrayList<CacheServer>();
		servers.addAll(activeServers.values());
		return servers;
	}

	public static CacheServer getActiveServer(String server){
		CacheServer cacheServer = activeServers.get(server);
		return cacheServer;
	}
	
	private static ScheduledExecutorService heartBeatPool = Executors.newScheduledThreadPool(1);
	public static void init() {
		if (!CacheConfig.isCacheEnable()) {
			return;
		}

		for (CacheServer server : CacheConfig.getServers()) {
			server.init();
			if(server.checkActive()){
				activeServers.put(server.toString(), server);
				CacheService.log("可用缓存服务器"+server);
			}else{
				downServers.put(server.toString(), server);
				CacheService.log("失效缓存服务器"+server);
			}
		}
		
		heartBeatPool.scheduleAtFixedRate(new Runnable() {
			public void run() {
				List<CacheServer> checkDownServers = new ArrayList<CacheServer>();
				for (CacheServer server : activeServers.values()) {
					if(!server.checkActive()){
						CacheService.log("缓存失效"+server);
						checkDownServers.add(server);
					}
				}
				List<CacheServer> checkActiveServers = new ArrayList<CacheServer>();
				for (CacheServer server : downServers.values()) {
					if (server.checkActive()) {
						try {
							CacheService.log("缓存恢复"+server);
							server.clear();
							checkActiveServers.add(server);
						} catch (Exception e) {
							logger.error("缓存异常", e);
						}
					}
				}
				for(CacheServer downServer: checkDownServers){
					activeServers.remove(downServer.toString());
					downServers.put(downServer.toString(), downServer);
				}
				
				for(CacheServer activeServer: checkActiveServers){
					downServers.remove(activeServer.toString());
					activeServers.put(activeServer.toString(), activeServer);
				}
			}
		}, CacheConfig.getHeartBeatInterval(), CacheConfig.getHeartBeatInterval(), TimeUnit.SECONDS);
	}
	
	private static class EmptyCacheServer extends CacheServer{
		protected boolean test() {return false;}
		public void init() {}
		public void set(String key, Object value) throws Exception {}
		public void mset(List<Object> keyValues) throws Exception {}
		public Object get(String key) throws Exception {return null;}
		public List<Object> mget(String... keys) throws Exception {return null;}
		public void remove(String key) throws Exception {}
		public void clear() throws Exception {}
		public Set<String> keys(String pattern) throws Exception {return null;}
	}
}